package org.osx.my2048.util;

import java.util.LinkedList;
import java.util.List;

/**
 * Some helpful methods.
 * 
 * @author O. Wu
 * @date 15/02/18
 */
public class Util {

	private Util() {
	}

	private interface Mergeable<E> {

		void merge(LinkedList<E> a, LinkedList<E> b, E value);
	}

	private static void metaMerge(LinkedList<Integer> lElem,
			LinkedList<Integer> lZero, Integer value) {
		if (value == 0) {
			lZero.add(0);
		} else if (!lElem.isEmpty()
				&& lElem.getLast().intValue() == value.intValue()) {
			lElem.set(lElem.size() - 1, value.intValue() << 1);
			lZero.add(0);
		} else {
			lElem.add(value);
		}
	}

	/**
	 * Merge the duplicate elements in <tt>array</tt>, and shift all elements
	 * with 0 at the tail of the array.
	 */
	public static Integer[] allMerge(List<Integer> array) {
		LinkedList<Integer> listElem = new LinkedList<Integer>();
		LinkedList<Integer> listZero = new LinkedList<Integer>();
		Mergeable<Integer> m = Util::metaMerge;

		// handle every element in array
		for (Integer n : array) {
			m.merge(listElem, listZero, n);
		}

		listElem.addAll(listZero);

		return listElem.toArray(new Integer[] {});
	}

	/**
	 * Return <tt>true</tt> only if <tt>a</tt> and <tt>b</tt> has the same
	 * content.
	 */
	public static boolean arrayEquals(int[] a, int[] b) {
		if (a.length != b.length) {
			return false;
		}
		for (int i = 0; i < b.length; i++) {
			if (a[i] != b[i]) {
				return false;
			}
		}
		return true;
	}

	public static boolean mergeAvaliable(int[] array, int numOfBlock) {
		for (int i = 0; i < numOfBlock; i++) {
			int iRow = i * numOfBlock;
			int iColumn = i;

			for (int j = 1; j < numOfBlock; j++) {
				int nRow = iRow + 1;
				int nColumn = iColumn + numOfBlock;

				if (array[iRow] == array[nRow]
						|| array[iColumn] == array[nColumn]) {
					return true;
				} else {
					iRow = nRow;
					iColumn = nColumn;
				}
			}
		}
		return false;
	}
}
